/*
 * @Author: wuqingchun
 * @Date: 2024-07-26 09:39:49
 * @Description: 
 * @LastEditors: wuqingchun
 * @LastEditTime: 2024-07-26 11:22:15
 */
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <thread>

const int ROUND = 5;
const int TIMES = 10000;
const int MAXSIZE = 1 << 20;

const int SIZE_UNIT = 256;


/*
测试结果
```
0:0x7f8c8418f010: 70, 43
1:0x7f8c8418f110: 15, 16
2:0x7f8c8418f210: 16, 15
3:0x7f8c8418f310: 16, 15
4:0x7f8c8418f410: 15, 15
5:0x7f8c8418f510: 16, 15
6:0x7f8c8418f610: 15, 15
7:0x7f8c8418f710: 15, 15
8:0x7f8c8418f810: 15, 15
9:0x7f8c8418f910: 14, 15
10:0x7f8c8418fa10: 15, 15
11:0x7f8c8418fb10: 15, 15
12:0x7f8c8418fc10: 15, 15
13:0x7f8c8418fd10: 15, 14
14:0x7f8c8418fe10: 15, 15
15:0x7f8c8418ff10: 1540, 15
16:0x7f8c84190010: 15, 15
17:0x7f8c84190110: 15, 15
18:0x7f8c84190210: 15, 14
19:0x7f8c84190310: 15, 14
20:0x7f8c84190410: 15, 15
21:0x7f8c84190510: 16, 13
22:0x7f8c84190610: 14, 14
23:0x7f8c84190710: 14, 15
24:0x7f8c84190810: 15, 15
25:0x7f8c84190910: 15, 15
26:0x7f8c84190a10: 14, 15
27:0x7f8c84190b10: 15, 15
28:0x7f8c84190c10: 15, 15
29:0x7f8c84190d10: 15, 14
30:0x7f8c84190e10: 14, 15
31:0x7f8c84190f10: 1399, 15
```
1、背景知识
缺页中断（page-fault）是当程序试图访问一个未被映射到物理内存中的虚拟内存页面时，由内存管理单元（MMU）触发的中断。

2、现象
1）第一页的访问没有出现耗时大的值
2）每次跨页访问时，耗时都比较大，微秒级别

3、怎么判断出现了跨页访问？
1）内存页以4K为单位，首地址可以被4K整除，即地址16进制形式低三位全为0
2）内存的首地址上一页，结束地址在下一页
3）0x7f8c84190f10 在0x7f8c84190000页，0x7f8c84191010（0x7f8c84190f10 + 256）在0x7f8c84191000页

4、判断
malloc申请内存时，第一页已经映射了对应的物理内存，因此在访问时不会发生缺页中断，页内内存的访问耗时基本相同；？？？这个不确定，依赖于具体实现
后续出现跨页访问时，新的一页没有映射对应的物理内存，访问时会触发缺页中断，导致第一次访问时的耗时比较大。

*/
void smooth_pagefault_by_write()
{
    void* pMem = malloc(MAXSIZE);
    if (pMem == nullptr)
    {
        return;
    }

    char *pcStart = (char*)pMem;
    for (int j = 0; j < MAXSIZE/SIZE_UNIT; j++)
    {
        auto t1 = std::chrono::steady_clock::now();
        memset(pcStart, 1, SIZE_UNIT);
        auto t2 = std::chrono::steady_clock::now();
        memset(pcStart, 2, SIZE_UNIT);
        auto t3 = std::chrono::steady_clock::now();
        printf("%d:%p: %lu, %lu\n", j, pcStart, (t2-t1).count(), (t3-t2).count());
        pcStart += SIZE_UNIT;
    }
}

void smooth_pagefault_by_read()
{
    void* pMem = malloc(MAXSIZE);
    if (pMem == nullptr)
    {
        return;
    }

    char acBuf[SIZE_UNIT] = {0};

    char *pcStart = (char*)pMem;
    for (int j = 0; j < MAXSIZE/SIZE_UNIT; j++)
    {
        auto t1 = std::chrono::steady_clock::now();
        memcpy(acBuf, pcStart, SIZE_UNIT);
        auto t2 = std::chrono::steady_clock::now();
        memset(pcStart, 2, SIZE_UNIT);
        auto t3 = std::chrono::steady_clock::now();
        printf("%d:%p: %lu, %lu\n", j, pcStart, (t2-t1).count(), (t3-t2).count());
        pcStart += SIZE_UNIT;
    }
}

int main(int argc, char** argv)
{
    smooth_pagefault_by_write();
    smooth_pagefault_by_read();

    return 0;
}
